#include "PayCenterMgr.h"
#include "CenterService.h"
#include "ProtoBuffer/ServerInternalCmd.pb.h"
#include "ProtoBuffer/ClientToServerCmd.pb.h"
#include "ProtoBuffer/ServerToClientCmd.pb.h"
#include "AccountMgr/CenterAccountMgr.h"
#include "Common/LogDefine.h"

PayCenterMgr::PayCenterMgr()
{
}

PayCenterMgr::~PayCenterMgr()
{}

bool PayCenterMgr::Init()
{
    bool result = false;
    bool retCode = false;
	RechargeRechargeCfgMap::const_iterator iter, iterEnd;
	PRODUCT_MAP::iterator findIter;
	const RechargeRechargeCfgMap* pRecharMap = nullptr;
	m_productCfgMap.clear();
	m_channPayOpenMap.clear();
	m_productIndexs.clear();

	m_Func[CENTER_TO_WEBPAY_PAY_ORDER_RSP] = &PayCenterMgr::WebPayOrderRsp;
	m_Func[CENTER_TO_WEBPAY_PAY_RSP] = &PayCenterMgr::PayRspFromWeb;
	m_Func[CENTER_TO_WEBPAY_YYB_CX_RSP] = &PayCenterMgr::CXyybResultFromWeb;

	IMessageDispatch *pMessageDispatch = g_GetCenterService()->GetServiceMessageDispatch();
	MMOLOG_PROCESS_ERROR(pMessageDispatch != nullptr);

	retCode = pMessageDispatch->registerServerHandler(EMODULE_ID_PAY, this);
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = pMessageDispatch->registerClientHandler(EMODULE_ID_PAY, this);
	MMOLOG_PROCESS_ERROR(retCode);

	pRecharMap = g_GetRechargeRechargeCfgTable()->GetRechargeRechargeCfgMap();
	MMOLOG_PROCESS_ERROR(pRecharMap != nullptr);

	iter = pRecharMap->begin();
	iterEnd = pRecharMap->end();
	for (; iter != iterEnd; iter++)
	{
		//默认的每个产品id都必须不一样
		findIter = m_productCfgMap.find(iter->second.defaultPoint);
		if (m_productCfgMap.end() != findIter)
			MMO_ASSERT(true);
		m_productCfgMap[iter->second.defaultPoint] = &iter->second;

		for (size_t i = 0; i < iter->second.vecRechargeRechargeChannelCfg.size(); i++)
		{
			const RechargeRechargeChannelCfgInfo& channCfg = iter->second.vecRechargeRechargeChannelCfg[i];
			PRODUCT_MAP& productmap = m_channProductCfgMap[channCfg.id];
			findIter = productmap.find(channCfg.point);
			if (productmap.end() != findIter)
				MMO_ASSERT(true);
			productmap[channCfg.point] = &iter->second;
		}
	}

    result = true;
Exit0:
	return result;

	return true;
}

bool PayCenterMgr::UnInit()
{
    bool result = false;
    bool retCode = false;
	IMessageDispatch *pMessageDispatch = g_GetCenterService()->GetServiceMessageDispatch();
	MMOLOG_PROCESS_ERROR(pMessageDispatch != nullptr);

	retCode = pMessageDispatch->unregisterServerHandler(EMODULE_ID_PAY);
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = pMessageDispatch->unregisterDBProxyHandler(EMODULE_ID_PAY);
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = pMessageDispatch->unregisterClientHandler(EMODULE_ID_PAY);
	MMOLOG_PROCESS_ERROR(retCode);

	m_productCfgMap.clear();

    result = true;
Exit0:
	return result;
}

void PayCenterMgr::onServerMessage(uint32_t actionId, RECV_PACKAGE &package)
{
	mFunc::iterator iter = m_Func.find(actionId);
	if (iter != m_Func.end())
		(this->*(iter->second))(package);
}

void PayCenterMgr::onClientMessage(uint32_t actionId, RECV_PACKAGE &package, uint64_t Id /* = 0 */)
{
	switch (actionId)
	{
	case CLIENT_TO_CENTER_PAY_REQ:
		ClientPayReq(package, Id);
		break;
	case CLIENT_TO_CENTER_PAY_ORDER_REQ:
		ClientPayOrderReq(package, Id);
		break;
	case CLIENT_TO_CENTER_YYB_CX:
		CXyybReq(package, Id);
		break;
	default:
		break;
	}
}

bool PayCenterMgr::ClientPayReq(RECV_PACKAGE& package, uint64_t cid)
{
    bool result = false;
    bool retCode = false;
	GamePayReq cpayReq;
	WebPayReq webReq;
	UidGameInfo* pUid = nullptr;
	PayInfo    *wpay = nullptr;
	const RechargeRechargeCfgInfo* pChargeInfo = nullptr;

	retCode = cpayReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	pUid = g_GetCenterAccountMgr()->GetUidGameInfoByCid(cid);
	if (pUid == nullptr)
	{
		LogErrFmtPrint("puid == null, productString:%s, chann:%d, cid:%lu", cpayReq.productid().c_str(), cpayReq.chanid(), cid);
		MMOLOG_PROCESS_ERROR(false);
	}

	wpay = webReq.mutable_pay();
	if (wpay == nullptr)
	{
		LogErrFmtPrint("wpay err, productString:%s, chann:%d, cid:%lu", cpayReq.productid().c_str(), cpayReq.chanid(), cid);
		MMOLOG_PROCESS_ERROR(false);
	}
	pChargeInfo = GetRechargeCfg(cpayReq.chanid(), cpayReq.productid());
	if (pChargeInfo == nullptr)
	{
		LogErrFmtPrint("wpay err config == null, productString:%s, chann:%d, cid:%lu", cpayReq.productid().c_str(), cpayReq.chanid(), cid);
		MMOLOG_PROCESS_ERROR(false);
	}

	wpay->set_zid(g_GetCenterService()->GetZoneId());
	wpay->set_channid(cpayReq.chanid());
	wpay->set_productid(cpayReq.productid());
	wpay->set_uid(pUid->uid);
	wpay->set_cid(cid);
	wpay->set_order("req");
	wpay->set_myorder(cpayReq.myoder());
	wpay->set_money(pChargeInfo->price);
	wpay->set_fakepay(false);

	webReq.set_paystring(cpayReq.paystring());

	//发送给网页支付服
	retCode = g_GetCenterService()->SendDataToWebPay(CENTER_TO_WEBPAY_PAY_REQ, &webReq);
	MMOLOG_PROCESS_ERROR(retCode);

	//打个日志
	PayDebugLog(wpay, "收到客户端充值请求,向支付服发送支付请求");

    result = true;
Exit0:
	return result;
}

bool PayCenterMgr::PayRspFromWeb(RECV_PACKAGE& package)
{
	bool result = false;
	bool retCode = false;
	WebPayRsp wrsp;
	GamePayRsp payRsp;
	WebPayNotifyRet notifyWeb;

	const RechargeRechargeCfgInfo* pChargeInfo = nullptr;
	PayInfo* pPayInfo = nullptr;

	retCode = wrsp.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	pPayInfo = wrsp.mutable_pay();
	MMOLOG_PROCESS_ERROR(pPayInfo != nullptr);

	payRsp.set_payret(wrsp.retcode());
	if (wrsp.retcode() != RET_SUCCESS)
	{
		payRsp.set_productid(pPayInfo->productid());
		retCode = g_GetCenterService()->SendDataToClient(pPayInfo->cid(), EMODULE_ID_PAY, CENTER_TO_CLIENT_PAY_RSP, &payRsp);
		MMOLOG_PROCESS_ERROR(retCode);
		goto Exit0;
	}

	//回复客户端充值消息
	payRsp.set_productid(pPayInfo->productid());
	payRsp.set_payrspstring(wrsp.payrspstring());

	//验证充值有效性
	pChargeInfo = GetRechargeCfg(pPayInfo->channid(), pPayInfo->productid());
	if (pChargeInfo == nullptr)
	{
		LogErrFmtPrint("PayCenterMgr::PayRspFromWeb pchargeInfo == null, productId:%s, cid:%lu, order:%s", pPayInfo->productid().c_str(), pPayInfo->cid(), pPayInfo->order().c_str());
		payRsp.set_payret(RET_PAY_INVALID_PAYMENT);
		retCode = g_GetCenterService()->SendDataToClient(pPayInfo->cid(), EMODULE_ID_PAY, CENTER_TO_CLIENT_PAY_RSP, &payRsp);
		MMOLOG_PROCESS_ERROR(retCode);
		goto Exit0;
	}

	//先不验证rmb，等接好支付sdk后恢复
	//if (uint32_t(pChargeInfo->price) != pPayInfo->money())
	//{
	//	char buf[200];
	//	snprintf(buf, 200, "充值失败,中心服RMB:%d  !=  支付RMB:%d", pChargeInfo->price, pPayInfo->money());
	//	PayDebugLog(pPayInfo, buf);
	//	MMOLOG_PROCESS_ERROR(false);
	//}

	g_GetCenterService()->SendDataToClient(pPayInfo->cid(), EMODULE_ID_PAY, CENTER_TO_CLIENT_PAY_RSP, &payRsp);

	//向逻辑服发道具
	retCode = SendCurrencyToLogic(pPayInfo);
	MMOLOG_PROCESS_ERROR(retCode);

	//通知webpay收到充值信息
	MMOLOG_PROCESS_ERROR(package.session != nullptr);
	notifyWeb.set_myorder(pPayInfo->myorder());
	notifyWeb.set_order(pPayInfo->order());
	retCode = g_GetCenterService()->SendData(package.session, EMODULE_ID_PAY, CENTER_TO_WEBPAY_NOTIFY_PAY, &notifyWeb);
	MMOLOG_PROCESS_ERROR(retCode);

	result = true;
Exit0:
	return result;
}

bool PayCenterMgr::SendCurrencyToLogic(PayInfo* payInfo)
{
    bool result = false;
    bool retCode = false;

	CurrencyLogic cl;
	PayInfo* clPayInfo = cl.mutable_payinfo();
	uint32_t logicId = 0;
	MMOLOG_PROCESS_ERROR(clPayInfo != nullptr);

	cl.set_count(1);
	clPayInfo->CopyFrom(*payInfo);
	logicId = g_GetCenterAccountMgr()->GetLogicIdByCid(payInfo->cid());
	if (logicId == 0)
	{
		PayDebugLog(payInfo, "中心服玩家不在线,发往db保存");
		retCode = g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_PAY, DBPROXY_PROTOCOL_SAVE_PAY_INFO, clPayInfo);
		MMOLOG_PROCESS_ERROR(retCode);
	}
	else
	{
		PayDebugLog(payInfo, "发送充值货币到逻辑服");
		retCode = g_GetCenterService()->SendDataToLogic(logicId, EMODULE_ID_PAY, CENTER_TO_LOGIC_PAY_CURRENCY_REQ, &cl);
		MMOLOG_PROCESS_ERROR(retCode);
	}

    result = true;
Exit0:
	return result;
}

bool PayCenterMgr::SendCurrencyToLogicFail(RECV_PACKAGE& package)
{
    bool result = false;
    bool retCode = false;
	uint32_t logicId = 0;

	CurrencyLogic cl;
	PayInfo* payinfo = nullptr;

	retCode = cl.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	payinfo = cl.mutable_payinfo();
	if (payinfo == nullptr)
	{
		LogErrFmtPrint("PayCenterMgr::SendCurrencyToLogicFail");
		MMOLOG_PROCESS_ERROR(false);
	}

	if (cl.count() > 2)
	{
		PayDebugLog(payinfo, "逻辑服发送失败,db保存");
		retCode = g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_PAY, DBPROXY_PROTOCOL_SAVE_PAY_INFO, payinfo);
		result = true;
		goto Exit0;
	}

	logicId = g_GetCenterAccountMgr()->GetLogicIdByCid(payinfo->cid());
	if (logicId == 0)
	{
		PayDebugLog(payinfo, "逻辑服发送失败且不在线,db保存");
		retCode = g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_PAY, DBPROXY_PROTOCOL_SAVE_PAY_INFO, payinfo);
		MMOLOG_PROCESS_ERROR(retCode);
	}
	else
	{
		PayDebugLog(payinfo, "逻辑服发送失败,重发到逻辑服");
		cl.set_count(cl.count() + 1);
		retCode = g_GetCenterService()->SendDataToLogic(logicId, EMODULE_ID_PAY, CENTER_TO_LOGIC_PAY_CURRENCY_REQ, &cl);
		MMOLOG_PROCESS_ERROR(retCode);
	}

    result = true;
Exit0:
	return result;
}

void PayCenterMgr::PayDebugLog(PayInfo* payInfo, string describe /* = "" */)
{
	rapidjson::Document doc;
	JsonObject obj(&doc);
	obj.AddUInt32("tid", TID_PAY_DEBUG);
	obj.AddUInt64("cid", payInfo->cid());
	obj.AddUInt32("uid", payInfo->uid());
	obj.AddString("product", payInfo->productid());
	obj.AddString("order", payInfo->order());
	obj.AddUInt32("money", payInfo->money());
	obj.AddString("describe", describe);
	obj.AddString("myoder", payInfo->myorder());
	obj.AddBool("fake", payInfo->fakepay());

	bool bsuc = g_GetCenterService()->SendLogToLogServer(obj);
	if (bsuc == false)
		LogErrFmtPrint("center player paylog error, cid:%lu, uid:%d", payInfo->cid(), payInfo->uid());
}

bool PayCenterMgr::ClientPayOrderReq(RECV_PACKAGE& package, uint64_t cid)
{
    bool result = false;
    bool retCode = false;

	GamePayOrderReq oreq;
	WebOrderReq weboReq;
	const RechargeRechargeCfgInfo* pChargeInfo = nullptr;

	retCode = oreq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	weboReq.set_channid(oreq.channid());
	weboReq.set_cid(cid);
	weboReq.set_zid(g_GetCenterService()->GetZoneId());
	if (oreq.has_orderstring())
		weboReq.set_orderstring(oreq.orderstring());
	//验证充值有效性
	pChargeInfo = GetRechargeCfg(oreq.channid(), oreq.productid());
	if (pChargeInfo == nullptr)
	{
		LogErrFmtPrint("PayCenterMgr::ClientPayOrderReq fail, cid:%lu, zid:%d, channid:%d, productId:%s", cid, weboReq.zid(), weboReq.channid(), oreq.productid().c_str());

		GamePayOrderRsp grsp;
		grsp.set_retcode(RET_PAY_REQ_ODER_CONF_ERR);
		g_GetCenterService()->SendDataToClient(cid, EMODULE_ID_PAY, CENTER_TO_CLIENT_PAY_ORDER_RSP, &grsp);
		MMOLOG_PROCESS_ERROR(false);
	}
	weboReq.set_money(pChargeInfo->price);
	weboReq.set_productid(oreq.productid());
	weboReq.set_productname(pChargeInfo->name);

	retCode = g_GetCenterService()->SendDataToWebPay(CENTER_TO_WEBPAY_PAY_ORDER_REQ, &weboReq);
	MMOLOG_PROCESS_ERROR(retCode);

	LogDebugFmtPrint("PayCenterMgr::ClientPayOrderReq, cid:%lu, zid:%d, channid:%d", cid, weboReq.zid(), weboReq.channid());

    result = true;
Exit0:
	return result;
}

bool PayCenterMgr::WebPayOrderRsp(RECV_PACKAGE& package)
{
    bool result = false;
    bool retCode = false;

	WebOrderRsp weboRsp;
	GamePayOrderRsp cwebOrsp;

	retCode = weboRsp.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	cwebOrsp.set_retcode(weboRsp.retcode());
	if (weboRsp.retcode() != RET_SUCCESS)
		goto Exit0;

	cwebOrsp.set_productid(weboRsp.productid());
	cwebOrsp.set_order(weboRsp.order());
	if (weboRsp.has_orderrspstring())
		cwebOrsp.set_orderstring(weboRsp.orderrspstring());
	if (weboRsp.has_cburl())
		cwebOrsp.set_cburl(weboRsp.cburl());

    result = true;
Exit0:
	g_GetCenterService()->SendDataToClient(weboRsp.cid(), EMODULE_ID_PAY, CENTER_TO_CLIENT_PAY_ORDER_RSP, &cwebOrsp);
	LogDebugFmtPrint("PayCenterMgr::WebPayOrderRsp, cid:%lu, channid:%d, retcode:%d", weboRsp.cid(), weboRsp.channid(), weboRsp.retcode());
	return result;
}

const RechargeRechargeCfgInfo* PayCenterMgr::GetRechargeCfg(uint32_t channId, string productId)
{
	CHANN_PRODUCT_MAP::iterator iter = m_channProductCfgMap.find(channId);
	if (iter != m_channProductCfgMap.end())
	{
		PRODUCT_MAP::iterator findIter = iter->second.find(productId);
		if (findIter != iter->second.end())
			return findIter->second;
	}
	else
	{
		PRODUCT_MAP::iterator findIter = m_productCfgMap.find(productId);
		if (findIter != m_productCfgMap.end())
			return findIter->second;
	}

	return nullptr;
}

void PayCenterMgr::UpdateOtherPayToLogic(uint32_t logicId /* = 0 */)
{
	UpdatePayToLogic updatePay;
	std::unordered_map<uint32_t, REPEATED_UINT32 >::iterator iter = m_productIndexs.begin();
	std::unordered_map<uint32_t, bool >::iterator iterOpen = m_channPayOpenMap.begin();

	for (; iter != m_productIndexs.end(); iter++)
	{
		UpdatePayToLogic::ChannPayIndex* cpIndex = updatePay.add_indexs();
		if (cpIndex == nullptr)
			continue;

		cpIndex->set_channid(iter->first);
		REPEATED_UINT32* pIndexs = cpIndex->mutable_indexs();
		if (pIndexs == nullptr)
			continue;

		pIndexs->CopyFrom(iter->second);
	}

	for (; iterOpen != m_channPayOpenMap.begin(); iterOpen++)
	{
		UpdatePayToLogic::ChannPayOpen* cpOpen = updatePay.add_payopens();
		if (cpOpen == nullptr)
			continue;

		cpOpen->set_channid(iterOpen->first);
		cpOpen->set_open(iterOpen->second);
	}
	if (logicId > 0)
	{
		if (!g_GetCenterService()->SendDataToLogic(logicId, EMODULE_ID_PAY, CENTER_TO_LOGIC_UPDATE_OTHER_PAY, &updatePay))
		   LogErrFmtPrint("send pay other info to logic:%d fail", logicId);
	}
	else
	{
	   if(!g_GetCenterService()->SendDataToAllLogic(EMODULE_ID_PAY, CENTER_TO_LOGIC_UPDATE_OTHER_PAY, &updatePay))
		   LogErrPrint("send pay other info to all logic fail");
	}
}

void PayCenterMgr::SetPayIndexs(uint32_t channId, REPEATED_UINT32 payIndex)
{
	m_productIndexs[channId] = payIndex;
}

void PayCenterMgr::SetPayOpen(uint32_t channId, bool bopen)
{
	m_channPayOpenMap[channId] = bopen;
}

void PayCenterMgr::RegisterWebPay()
{
	WebPayRegister webPayReg;
	webPayReg.set_zid(g_GetCenterService()->GetZoneId());

	if (!g_GetCenterService()->SendDataToWebPay(CENTER_TO_WEB_PAY_REGISTER, &webPayReg))
		LogErrPrint("PayCenterMgr::RegisterWebPay send fail");
}

bool PayCenterMgr::CXyybReq(RECV_PACKAGE& package, uint64_t cid)
{
    bool result = false;
    bool retCode = false;
	YYBcxReq cxReq;
	YYbCxWebReq cxWebReq;
	retCode = cxReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	cxWebReq.set_zid(g_GetCenterService()->GetZoneId());
	cxWebReq.set_cid(cid);
	cxWebReq.set_cxstring(cxReq.cxstring());

	if (!g_GetCenterService()->SendDataToWebPay(CENTER_TO_WEBPAY_YYB_CX_REQ, &cxWebReq))
		LogErrPrint(" PayCenterMgr::CXyybReq send fail");

	LogDebugFmtPrint("PayCenterMgr::CXyybReq, send to payweb, cid:%lu", cid);

    result = true;
Exit0:
	return result;
}

bool PayCenterMgr::CXyybResultFromWeb(RECV_PACKAGE& package)
{
    bool result = false;
    bool retCode = false;
	YYbCxWebRsp cxWebRsp;
	YYBcxRsp    cxRsp;
	retCode = cxWebRsp.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	cxRsp.set_balance(cxWebRsp.blance());

	retCode = g_GetCenterService()->SendDataToClient(cxWebRsp.cid(), EMODULE_ID_PAY, CENTER_TO_CLIENT_YYB_CX, &cxRsp);
	MMOLOG_PROCESS_ERROR(retCode);

	LogDebugFmtPrint(" PayCenterMgr::CXyybResultFromWeb, sucess cid:%lu, blance:%d", cxWebRsp.cid(), cxWebRsp.blance());

    result = true;
Exit0:
	return result;
}
